2018.10.15 星期一 14:35
this 几个实例
this关键字被用于指代当前的对象,通常,this指代的是方法中正在被调用的对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71// ## 1
var name='window'
var foo={
name:'foo',
hi:function(){
console.log(this.name)
},
bar:{
name:'bar',
say:function(){
console.log(this.name)
}
}
}
var hello=foo.hi;
hello();// window
foo.hi();// foo
foo.bar.say();// bar
// ## 2
var obj={
name:'obj',
times:[1,2,3,4],
print:function(){
this.times.map(function(v){
console.log(this.name)
})
}
}
obj.print(); // 4个undefined
// ### 改进
var obj={
name:'obj',
times:[1,2,3,4],
print:function(){
this.times.map(function(v){
console.log(this.name)
}.bind(this))
}
}
obj.print(); // 4个obj
// ## 3
var myObj = {
specialFunction: function () {
},
anotherSpecialFunction: function () {
},
getAsyncData: function (cb) {
console.log(this) // myObj
cb();
},
render: function () {
var that = this;
this.getAsyncData(function () {
console.log(this) // window
that.specialFunction();
that.anotherSpecialFunction();
});
this.specialFunction()
}
};
myObj.render();
/* cb: 在这种情况下--$PS:也就是回调函数,没有设置内部函数的this,所以它指向 global/window 对象(即非严格模式下调用的函数未设置this时指向的默认对象)。
同理setTimeout中的回调函数;如果使用箭头函数,this与封闭词法上下文的this保持一致
包括下面的情况
*/
<button onclick="alert((function(){return this})());">
Show inner this
</button>
call,apply 和bind
bind
bind:基于一个现有函数,创建一个新函数,同时提前绑定函数中的this为指定对象。
何时使用: 今后只要希望将一个对象和一个函数中的this,永久绑定,只能用bind。
原理:
1. 创建了一个新函数
2. 在新函数中调用了原函数
3. 永久绑定函数中的this为指定对象。
用法:
基于fun创建一个新函数fun1,并永久绑定fun1中的this为obj
基于fun创建一个新函数fun1,并永久绑定fun1中的this为obj,同时永久绑定fun1中的参数值为参数1,….1
2var fun1=fun.bind(obj);
var fun1=fun.bind(obj,参数1,...)
$PS: 在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。1
2
3
4
5
6
7
8var bar = function(){console.log(this.x);}
var foo = {x:3}
var sed = {x:4}
var func = bar.bind(foo).bind(sed);
func(); //3
var fiv = {x:5}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //3
call,apply和bind 比较
#### call apply:IE8+
相同点:临时借(调)用函数,临时替换函数中的this为指定对象。
不同点:传递给借用的函数的参数:
call,要求每个参数独立传入
apply,要求所有参数用数组或集合方式整体传入。
强调: 不创建新函数,而是直接调用原函数。
#### bind: IE9+
相同:都是为了替换函数中的this为指定对象。
不同:
1.创建一个新函数。
2.永久绑定this为指定对象,且也可永久绑定部分参数值。
$PS: bind是返回对应函数,便于稍后调用;apply、call则是立即调用 。
$TODO: 模拟实现bind函数
使用
为了巩固加深记忆,下面列举一些常用用法:
1、数组之间追加1
2
3
4var array1 = [12 , "foo" , {name:"Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为 [12 , "foo" , {name:"Joe"} , -2458 , "Doe" , 555 , 100] */
2、获取数组中的最大值和最小值
number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。1
2
3var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
3、验证是否是数组(前提是toString()方法没有被重写过)1
2
3functionisArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
4、类(伪)数组使用数组方法var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。
$PS: log函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function log(){
console.log.apply(console, arguments);
};
log(1); //1
log(1,2); //1 2
// ## 1
function log(msg){
console.log(msg);
};
// ## 2
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
// ## 0
// log=console.log.bind(this)
log=console.log.bind(this,'app|')
log(1,2); //app| 1 2
14:46
2018.10.29 星期一 11:25
this 关键字
# this
与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。
在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。ES5引入了bind方法来设置函数的this值,而不用考虑函数如何被调用的,ES2015 引入了支持this词法解析的箭头函数(它在闭合的执行上下文内设置this的值)。
## 全局上下文
无论是否在严格模式下,在全局执行上下文中(在任何函数体外部)this 都指代全局对象。1
2
3this === window
var a=22
this.a // 22
## 函数上下文
在函数内部,this的值取决于函数被调用的方式。
简单调用
因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象。
$PS: 可以理解成对象调用,即全局window调用,所以指向全局对象:window
然而,在严格模式下,this将保持他进入执行上下文时的值,所以下面的this将会默认为undefined。
所以,在严格模式下,如果 this 没有被执行上下文(execution context)定义,那它将保持为 undefined。1
2
3
4
5
6
7function f(){
console.log(this) // window
}
function f(){
console.log(this) // undefined
}
bind方法
$PS_兼容: #1 [Understanding JavaScript Bind ()]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
箭头函数节
在箭头函数中,this与封闭词法上下文的this保持一致。在全局代码中,它将被设置为全局对象($PS: 也是当前定义是的上下文)
作为对象的方法节
当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。
#### 原型链中的 this
对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。
#### getter 与 setter 中的 this
再次,相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
作为构造函数节
当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。
作为一个DOM事件处理函数节
当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。
作为一个内联事件处理函数节
当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素:1
2
3
4
5
6
7
8
9<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
<!-- 上面的 alert 会显示button。注意只有外层代码中的this是这样设置的: -->
<button onclick="alert((function(){return this})());">
Show inner this
</button>
<!-- 在这种情况下,没有设置内部函数的this,所以它指向 global/window 对象(即非严格模式下调用的函数未设置this时指向的默认对象)。 -->
其他参考:
Understanding JavaScript Bind ()
测试
1 | // ## example 1 |
11:40